<!DOCTYPE html PUBLIC "-//WAPFORUM//DTD XHTML Mobile 1.0//EN" "http://www.wapforum.org/DTD/xhtml-mobile10.dtd">
<html>
  <head>
  <meta http-equiv="content-type" content="text/html; charset=utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, user-scalable=yes">
  
  
  <title>  Java Interface一个知识点 |   XHX 博客 </title>

 
  
    <link rel="icon" href="/images/favicon.ico">
  


  <link rel="stylesheet" href="/nayo.min.css"> 
</head>  
  <body>   
    
      <header class="header">
	
  <nav class="header-nav">        

    <span class="iconfont icon-menu mobile-toggle"></span>   	

    <div class="header-logo">
      <a href="/">
        <img class="header-logo-img" src="/images/head.JPG">
      </a>
    </div>

    <div class="header-menu">          
              
          
            <a class="header-menu-link" id="header-menu-home" href="/">
              <i class="iconfont icon-home">  
            </i></a>     
          
              
          
            <a class="header-menu-link" id="header-menu-archives" href="/archives">
              <i class="iconfont icon-archives">  
            </i></a>     
          
              
          
            <a class="header-menu-link" id="header-menu-tags" href="/tags">
              <i class="iconfont icon-tags">  
            </i></a>     
          
              
          
            <a class="header-menu-link" id="header-menu-about" href="/about">
              <i class="iconfont icon-about">  
            </i></a>     
          
              
          
              <a class="header-menu-link" id="header-menu-search">
                <i class="iconfont icon-search">  
              </i></a>
          
                  
    </div>  
    
  </nav>
</header>

   

      <div class="container">       
          
          
            <section class="main">  
          

          <article class="post">
  
	<div class="post-header">

	<p class="post-title">	
		Java Interface一个知识点
	</p>
			

	<div class="meta-info">	
	<span>
		Sep 26, 2018
	</span>

	
	
		<i class="iconfont icon-words"></i>
		<span>
			2082
		</span>
	
</div>

</div> 
	
    <script type="text/x-mathjax-config">
        var post = document.getElementsByClassName("post")[0];  
        MathJax.Hub.Config({
            showProcessingMessages: false,
            messageStyle: "none",    
            tex2jax: {
                inlineMath:  [ ["$", "$"] , ["\\(","\\)"]],
                displayMath: [ ["$$","$$"] , ["\\[","\\]"]],
                skipTags: ['script', 'noscript', 'style', 'textarea', 'pre','code','a'],
            },
            "HTML-CSS": {            
                showMathMenu: false
            }
        });
        MathJax.Hub.Queue(["Typeset",MathJax.Hub,post]);
    </script>
    <style>.MathJax{outline:0;}</style>

    <script type="text/javascript" src="//cdn.bootcss.com/mathjax/2.7.2/latest.js?config=TeX-AMS-MML_HTMLorMML"></script>
 

	  <div class="typo post-content slideDownMin">

		

			
					<h2 id="引言"><a href="#引言" class="headerlink" title="引言"></a>引言</h2><p>   最近在看 Tomcat 实现相关的书籍，阅读到这样一句：“若只使用如下语句，编译器就无法知道要调用哪个构造函数，并且会报错：new URL(null, str, null)” 。就忽然想去探究一下编译器在考虑有继承的类作为参数的函数执行过程的逻辑。于是就有了这篇文章。<br>   <a id="more"></a></p>
<h2 id="1"><a href="#1" class="headerlink" title="1"></a>1</h2><p>   考虑如下代码：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Parent</span></span>&#123;&#125;</span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Son</span> <span class="keyword">extends</span> <span class="title">Parent</span></span>&#123;&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">InterfaceTest</span></span>&#123;</span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">test</span><span class="params">(Parent obj)</span> </span>&#123;</span><br><span class="line">        System.out.println(<span class="string">"Method with Parent"</span>);</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">test</span><span class="params">(Son obj)</span> </span>&#123;</span><br><span class="line">        System.out.println(<span class="string">"Method with Son"</span>);</span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> </span>&#123;</span><br><span class="line">        <span class="comment">//test1</span></span><br><span class="line">        test(<span class="keyword">new</span> Parent());</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p>   这里输出是：<br><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">Method with Parent</span><br></pre></td></tr></table></figure></p>
<p>   这里应该不用解释了，new 出来的就是一个 Parent 对象，因此调用的自然是 Parent 为参数的方法。</p>
<hr>
<h2 id="2"><a href="#2" class="headerlink" title="2"></a>2</h2><p>   考虑如下代码：<br><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">...</span><br><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> </span>&#123;</span><br><span class="line">    <span class="comment">//test2</span></span><br><span class="line">    Parent p = <span class="keyword">new</span> Son();</span><br><span class="line">    test(p);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></p>
<p>   这里输出是：<br><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">Method with Parent</span><br></pre></td></tr></table></figure></p>
<p>   变量 p 声明的类型是 Parent，因此虽然它 new 的时候是Son，但是在传递值给 p 的时候已经擦除为 Parent 类型了，在后面，除非主动转换(显式转换)类型，不然它是 Son 的真相就被雪藏了。所以这里 test 方法只知道它是 Parent，因此调用的是 Parent 为参数的方法。</p>
<hr>
<h2 id="3"><a href="#3" class="headerlink" title="3"></a>3</h2><p>   考虑如下代码：<br><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">...</span><br><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> </span>&#123;</span><br><span class="line">    test(<span class="keyword">null</span>);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></p>
<p>   这里输出是：<br><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">Method with Son</span><br></pre></td></tr></table></figure></p>
<p>   这里开始就很有意思了，这一部分为什么会输出 Son 呢？2个 test 难道不是都符合条件？这里参考了文章[Java函数重载和精准度匹配][1]，简单说就是因为参数为 Son 的函数比参数为 Parent 的函数更精确。不过文章并没有深入去探究原因，后续计划有时间去查 Java 运行时的原理。<br>   通过查看编译后的字节码，可以得到的信息：Java 编译器在编译时就已经确定<code>test(null)</code>要执行的是 <code>test(Son)</code> 这个函数，指向的函数引用已经是test(Son)，甚至test(Parent)都没有放到 ConstantPool 里面。</p>
<h2 id="4"><a href="#4" class="headerlink" title="4"></a>4</h2><p>   考虑如下代码：<br><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Parent</span></span>&#123;&#125;</span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Son</span> <span class="keyword">extends</span> <span class="title">Parent</span></span>&#123;&#125;</span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Daughter</span> <span class="keyword">extends</span> <span class="title">Parent</span></span>&#123;&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">InterfaceTest</span></span>&#123;</span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">test</span><span class="params">(Parent obj)</span> </span>&#123;</span><br><span class="line">        System.out.println(<span class="string">"Method with Parent"</span>);</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">test</span><span class="params">(Son obj)</span> </span>&#123;</span><br><span class="line">        System.out.println(<span class="string">"Method with Son"</span>);</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">test</span><span class="params">(Daughter obj)</span> </span>&#123;</span><br><span class="line">        System.out.println(<span class="string">"Method with Daughter"</span>);</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> </span>&#123;</span><br><span class="line">        test(<span class="keyword">null</span>);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></p>
<p>   这里输出是：<br><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">Error: Ambiguous method call. Both test(Son) in InterfaceTest and test(Daughter) in InterfaceTest match.</span><br></pre></td></tr></table></figure></p>
<p>   这里出现异常了。是因为调用的 test 方法存在二义性：test(Son) 和 test(Daughter) 都满足条件，无法判断调用哪一个。</p>
<hr>
<h2 id="后续"><a href="#后续" class="headerlink" title="后续"></a>后续</h2><p>   其实这部分最重要的知识点就是：在可以选择多个执行方法的时候，编译器如何选择？答案是：选择一个最具体的函数执行。具体执行过程参见文章：<a href="/2018/09/26/java-如何选择最具体的方法执行（翻译）/">java 如何选择最具体的方法执行（翻译）</a></p>
<p>参考资料：<br>[1]: <a href="https://blog.csdn.net/smartyidiot/article/details/7464454" target="_blank" rel="noopener">https://blog.csdn.net/smartyidiot/article/details/7464454</a> Java函数重载及精准度匹配</p>
<p>[2]: <a href="https://docs.oracle.com/javase/specs/jls/se8/html/jls-15.html#jls-15.12.2.5" target="_blank" rel="noopener">https://docs.oracle.com/javase/specs/jls/se8/html/jls-15.html#jls-15.12.2.5</a> Choosing the Most Specific Method</p>
  	
					
	  </div>     
	  

	<div class="post-footer">

  <div class="post-footer-other">
      <span class="post-footer-item">
        




<span class="donate-btn">
	<span class="iconfont icon-donate"></span>
</span>


<div id="donate-box" class="sildeUpMin">

	<span class="donate-cancel iconfont icon-cancel"></span>

	<div class="donate-img-box">
		<img id="donate-qr-wechat" class="noLazyLoad donate-img" src="/images/donate1.png" alt="No Donate Image!">	
		<img id="donate-qr-alipay" class="noLazyLoad donate-img" src="/images/donate2.png" alt="No Donate Image!">	
	</div>

	<span class="donate-word">希望本文对你有帮助~</span>

	<div class="donate-list">
		<span class="iconfont icon-donate-wechat"></span>
		<span class="iconfont icon-donate-alipay"></span>
	</div>

</div>

 
      </span>           
      <span class="post-footer-item">
        
	
<script id="-mob-share" src="http://f1.webshare.mob.com/code/mob-share.js?appkey=29a4323345125"></script>
	
	<span class="share-btn">
	<span class="iconfont icon-share"></span>
	</span>


	<div class="-mob-share sildeUpMin">
		<div class="-mob-inner">
		   			             
            <a class="iconfont icon-share-qq -mob-share-link"></a>		
     	   			             
            <a class="iconfont icon-share-weixin -mob-share-link"></a>		
     	   			             
            <a class="iconfont icon-share-weibo -mob-share-link"></a>		
     	   
		</div>
	</div>	

      </span>           
  </div>  

  <div class="post-footer-meta">
        	

        
          <i class="iconfont icon-tag"></i>     
            <a class="tag-link" href="/tags/Java/">Java</a>    
        	
  </div>

</div>


<nav class="post-footer-nav">
  
    <div class="post-footer-link">
      <a href="/2018/09/26/java-如何选择最具体的方法执行（翻译）/" id="post-nav-newer" class="post-nav-link-wrap">
        <strong class="post-nav-caption">newer</strong>
           
          <a class="post-nav-title" href="/2018/09/26/java-如何选择最具体的方法执行（翻译）/">
          java 如何选择最具体的方法执行（翻译）</a>
      </a>
    </div>
  
  
    <div class="post-footer-link">
      <a href="/2018/07/02/Mac-OS上搭建虚拟机集群/" id="post-nav-older" class="post-nav-link-wrap">
        <strong class="post-nav-caption">older</strong>
        
          <a class="post-nav-title" href="/2018/07/02/Mac-OS上搭建虚拟机集群/">
          Mac OS上搭建网络连通的虚拟机集群😊</a>
      </a>
    </div>
  
</nav>
 
	


    
    <div id="disqus_thread"></div>

    <script>
    (function() { 
    var d = document, s = d.createElement('script');
    s.src = 'https://'+'xiaohaoxing-github-io'+'.disqus.com/embed.js';
    s.setAttribute('data-timestamp', +new Date());    
    (d.head || d.body).appendChild(s);
    })();
    </script>

    <noscript>Please enable JavaScript to view the  <a href="https://disqus.com/?ref_noscript">comments powered by Disqus.</a>
    </noscript>


	
</article>

          </section> 
      </div>            
    
    <a id="backTop">
      <span>
        <i class="iconfont icon-backtotop"></i>
      </span>
    </a> 

  
    
    <div class="search-container sildeUpMin">
        <div class="search-header">
            <input type="text" placeholder="输入你想搜索的" id="search-input" class="search-input">
            <span class="search-cancel">
                <i class="iconfont icon-cancel">
            </i></span>
        </div>
        <div id="search-result" class="search-result"></div>
    </div>
 
     <div class="mobile-menu">      

      
      <img class="mobile-menu-icon" src="/images/favicon.ico">   
      

         
            

            <a class="mobile-menu-link" href="/">首頁
            </a>
            
         
            

            <a class="mobile-menu-link" href="/archives">歸檔
            </a>
            
         
            

            <a class="mobile-menu-link" href="/tags">標籤
            </a>
            
         
            

            <a class="mobile-menu-link" href="/about">關於
            </a>
            
         
                          

            <a class="mobile-menu-link mobile-menu-search" href="#">搜索 </a>                 
            
         
      
</div>        
    



     
    




<footer id="footer">	    

		
		<div class="footer-copyright">
		&copy;
				
		2018-
		
		2019		
	
		XiaoHaoxing
		<br>

		Theme By
		<a href="https://github.com/Lemonreds/hexo-theme-Nayo" target="_blank">Nayo</a>	
		</div>			
		<script src="https://s19.cnzz.com/z_stat.php?id=1274862886&web_id=1274862886" language="JavaScript"></script>
</footer>   

  

    <script src="/nayo.bundle.js"></script>           
  </body>        
</html>